/**
 * 
 */
package fr.lelouet.ga.algorithmes;

import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Set;

import fr.lelouet.ga.*;

/**
 * @author le louet
 */
public abstract class AAlgorithme<T> implements Algorithm<T>, Combinator<T>,
    Generator<T>, Mutator<T>, Reducer<T>, Stopper<T> {

  protected static enum NextStates {
    dunno, isnext, nonext
  }

  protected Generation<T> generation;

  protected NextStates state;

  @Override
  public boolean hasNext() {
    if (this.state == NextStates.dunno) {
      if (!this.stop(this.generation)) {
        this.state = NextStates.isnext;
      } else {
        this.state = NextStates.nonext;
      }
    }
    return this.state == NextStates.isnext;
  }

  @Override
  public Iterator<Generation<T>> iterator() {
    this.reinit();
    return this;
  }

  @Override
  public Generation<T> next() {
    if (!this.hasNext()) {
      throw new NoSuchElementException();
    }
    this.state = NextStates.dunno;
    final Set<T> combinated = this.combination(this.generation);
    this.mute(this.generation);
    this.generation.addAll(combinated);
    final Set<T> toremove = this.toReduce(this.generation);
    this.generation.removeAll(toremove);

    return this.generation;

  }

  /** forces the algorithme to start a new search */
  public void reinit() {
    this.generation = this.generate();
    this.state = NextStates.dunno;
    this.restart();
  }

  @Override
  public void remove() {
    throw new UnsupportedOperationException();
  }
}
